#ifndef MY_GLOBALS_H
#define MY_GLOBALS_H
#endif

#include <string>
#include <allegro5\allegro.h>
#include <allegro5\allegro_image.h>
#include <allegro5\allegro5.h>

#define PI 3.14159265

/*
* Global Variables
*/
extern const int WIDTH;
extern const int HEIGHT;
extern const int FPS;
extern const int TILE_WIDTH;
extern const int TILE_HEIGHT;
extern const float HERO_SPEED;
extern const float GRAVITY;


enum JUMP{CONSTANT , TOGGLE};
JUMP jump_type = TOGGLE;



enum KEYS {UP , DOWN , LEFT , RIGHT , ESCAPE};
bool keys[5] = {false, false , false , false , false};
bool last_keys[5] = {false , false , false , false , false};




//======================================================
enum GAME_STATES{MAIN_MENU , RUN_GAME , GAME_OVER}; // has to be changed according to the game

class MY_STATE_MACHINE
{
	public:
		GAME_STATES current_state;
		int number_of_states;

		MY_STATE_MACHINE (int nos);
};

MY_STATE_MACHINE::MY_STATE_MACHINE(int nos)
{
	if(nos < 1)
		number_of_states = 1;
	else
		number_of_states = nos;
	current_state = MAIN_MENU;
};

//======================================================

#define MY_STANDARD_FRAME_DELAY 5;
enum MY_ANIMATION_DIR {MY_ANIMATION_DIR_FORWARD=1 , MY_ANIMATION_DIR_REVERSE=-1};
enum MY_LOOP_TYPE {MY_SIMPLE_LOOP , MY_PING_PONG_LOOP};

class MY_GRAPHIC
{
	public:
		short int max_frames;
		short int cur_frame;
		short int frame_counter;
		short int frame_delay;
		short int ping_frame;
		short int pong_frame;
		int frame_width;
		int frame_height;
		short int num_columns;
		short int animation_dir;
		
		float scale_horizontal;
		float scale_vertical;
		bool invert_horizontal;
		bool invert_vertical;
		MY_LOOP_TYPE loop_type;
		

		ALLEGRO_BITMAP *image;

		MY_GRAPHIC(short int max_f , short int num_col , int f_width , int f_height , ALLEGRO_BITMAP *im);
		MY_GRAPHIC(short int max_f , short int num_col , int f_width , int f_height , ALLEGRO_BITMAP *im , short int ping_f , short int pong_f);
};

MY_GRAPHIC::MY_GRAPHIC(short int max_f , short int num_col , int f_width , int f_height , ALLEGRO_BITMAP *im)
{
	max_frames = max_f;
	cur_frame = 0;
	frame_counter = 0;
	frame_delay = MY_STANDARD_FRAME_DELAY;
	frame_width = f_width;
	frame_height = f_height;
	num_columns = num_col;
	animation_dir = MY_ANIMATION_DIR_FORWARD;
	scale_horizontal = 1.0;
	scale_vertical = 1.0;
	invert_horizontal = false;
	invert_vertical = false;
	loop_type = MY_SIMPLE_LOOP;
	ping_frame = 0;
	pong_frame = max_f - 1;

	image = im;
}

MY_GRAPHIC::MY_GRAPHIC(short int max_f , short int num_col , int f_width , int f_height , ALLEGRO_BITMAP *im , short int ping_f , short int pong_f)
{
	max_frames = max_f;
	cur_frame = 0;
	frame_counter = 0;
	frame_delay = MY_STANDARD_FRAME_DELAY;
	frame_width = f_width;
	frame_height = f_height;
	num_columns = num_col;
	animation_dir = MY_ANIMATION_DIR_FORWARD;
	scale_horizontal = 1.0;
	scale_vertical = 1.0;
	invert_horizontal = false;
	invert_vertical = false;
	loop_type = MY_PING_PONG_LOOP;
	ping_frame = ping_f;
	pong_frame = pong_f;

	image = im;
}

//======================================================
enum MY_COLLISION{MY_COLLIDABLE , MY_NOT_COLLIDABLE};
enum MY_H_MOV{MY_H_MOV_LEFT , MY_H_MOV_RIGHT};
class MY_ELEMENT
{
	public:
		int id;
		float x;
		float y;
		float bound_x;
		float bound_y;
		float vel_x;
		float vel_y;
		bool live;
		bool show_collision_boundaries;
		MY_COLLISION collision_type;
		
		MY_GRAPHIC * graphic;

		MY_ELEMENT(int id , MY_GRAPHIC *graph);
		void draw(void);
		void draw(float xOff , float yOff);
		void set_position(float new_x , float new_y);
		void set_vel(float new_vel_x , float new_vel_y);
		void set_live(bool is_live);
		void set_graphic(MY_GRAPHIC *graph);
		void update(void);

		// specific for player element
		float last_jump_height;
		int jump_power;
		int current_jump_power;
		bool can_jump_again;
		bool is_jumping;
		

		void jump(void);
		void reset_jump();
};

MY_ELEMENT::MY_ELEMENT(int i , MY_GRAPHIC *graph)
{
	id = i;
	x = 0.0;
	y = 0.0;
	vel_x = 0.0;
	vel_y = 0.0;
	live = false;
	graphic = graph;
	bound_x = graph->frame_width/2;
	bound_y = graph->frame_height/2;
	show_collision_boundaries = false;
	collision_type = MY_COLLIDABLE;
	
	//specific for player element
	last_jump_height = y;
	jump_power = 5;
	current_jump_power = jump_power;
	can_jump_again = true;
	is_jumping = false;
}

void MY_ELEMENT::draw(void)
{
	if(live)
	{
		ALLEGRO_BITMAP *current_frame = NULL;
		int fx = (graphic->cur_frame % graphic->num_columns) * graphic->frame_width;
		int fy = (graphic->cur_frame / graphic->num_columns) * graphic->frame_height;
		current_frame = al_create_sub_bitmap(graphic->image , fx , fy , graphic->frame_width , graphic->frame_height);
		int flip_hor = 0;
		if(graphic->invert_horizontal)
			flip_hor |= ALLEGRO_FLIP_HORIZONTAL;
		if(graphic->invert_vertical)
			flip_hor |= ALLEGRO_FLIP_VERTICAL;
		al_draw_scaled_bitmap(current_frame , 0 , 0 , graphic->frame_width , graphic->frame_height , 
			x - (graphic->frame_width /2)*(graphic->scale_horizontal) , y - (graphic->frame_height / 2)*(graphic->scale_vertical) , 
			graphic->frame_width * graphic->scale_horizontal , graphic->frame_height * graphic->scale_vertical , flip_hor);
	
		if(show_collision_boundaries == true && collision_type != MY_NOT_COLLIDABLE)
			al_draw_filled_rectangle(x - bound_x , y-bound_y , x+bound_x , y + bound_y , al_map_rgba(255 , 180 , 200 , 10));
	}
}

void MY_ELEMENT::draw(float xOff , float yOff)
{
	if(live)
	{
		ALLEGRO_BITMAP *current_frame = NULL;
		int fx = (graphic->cur_frame % graphic->num_columns) * graphic->frame_width;
		int fy = (graphic->cur_frame / graphic->num_columns) * graphic->frame_height;
		current_frame = al_create_sub_bitmap(graphic->image , fx , fy , graphic->frame_width , graphic->frame_height);
		int flip_hor = 0;
		if(graphic->invert_horizontal)
			flip_hor |= ALLEGRO_FLIP_HORIZONTAL;
		if(graphic->invert_vertical)
			flip_hor |= ALLEGRO_FLIP_VERTICAL;


		al_draw_scaled_bitmap(current_frame , 0 , 0 , graphic->frame_width , graphic->frame_height , 
			(x - xOff - (graphic->frame_width /2))*(graphic->scale_horizontal) , y - (graphic->frame_height / 2)*(graphic->scale_vertical) , 
			graphic->frame_width * graphic->scale_horizontal , graphic->frame_height * graphic->scale_vertical , flip_hor);

		// uncomment to visualize the center of the element
		//al_draw_filled_rectangle(x - bound_x , y-bound_y , x+bound_x , y + bound_y , al_map_rgba(255 , 180 , 200 , 180));
	}
}

void MY_ELEMENT::update(void)
{
	if(live)
	{
		x += vel_x;
		y += vel_y;
		
		if(++ (graphic->frame_counter) >= graphic->frame_delay)
		{
			graphic->cur_frame += graphic->animation_dir;
			switch(graphic->loop_type)
		{
			case MY_PING_PONG_LOOP:
				if(graphic->cur_frame >= graphic->pong_frame)
					graphic->animation_dir = MY_ANIMATION_DIR_REVERSE;
				else if((graphic->cur_frame <= graphic->ping_frame) && (graphic->animation_dir == MY_ANIMATION_DIR_REVERSE))
					graphic->animation_dir = MY_ANIMATION_DIR_FORWARD;
				graphic->frame_counter = 0;
				break;
			default:
				if(graphic->cur_frame >= graphic->max_frames)
					graphic->cur_frame = 0;
				else if(graphic->cur_frame <= 0)
					graphic->cur_frame = graphic->max_frames -1;
				graphic->frame_counter = 0;
				break;
		}
			
		}
	}
}


void MY_ELEMENT::set_graphic(MY_GRAPHIC *graph)
{
	graphic = graph;
}

// specific for player element
void MY_ELEMENT::jump(void)
{
	if((current_jump_power > 0))
	{
		if(vel_y >0)
			vel_y = 0;
		current_jump_power -= 1;
		vel_y -= 1.3; 
		is_jumping = true;
		can_jump_again = false;
	}
	else
		is_jumping = false;
}

void MY_ELEMENT::reset_jump()
{
	if(can_jump_again) 
		current_jump_power = jump_power;
	is_jumping = false;
}

//======================================================

class MY_CAMERA
{
public:
	int screen_width;
	int screen_height;
	float x;
	float y;
	float scale_x;
	float scale_y;
	int pam_y;

	MY_CAMERA(int width , int height);
	void update(ALLEGRO_TRANSFORM *cam ,MY_ELEMENT *centered  , int map_width , int map_height);
};

MY_CAMERA::MY_CAMERA(int width , int height)
{
	screen_width = width;
	screen_height = height;
	x = 0;
	y = 0;
	scale_x = 2.0;
	scale_y = 2.0;
	pam_y = 80;
	
}

void MY_CAMERA::update(ALLEGRO_TRANSFORM *cam ,MY_ELEMENT *centered  , int map_width , int map_height)
{
	x = -(screen_width/(2*scale_x)) + centered->x;
	y = -(screen_height/(2*scale_y)) + centered->y;
	if(x < 0)
		x = 0;
	if(x > (map_width - screen_width/(scale_x)))
		x = (map_width - screen_width/(scale_x));
	if(y < 0)
		y = 0;
	if( y > (map_height - screen_height/(scale_y)))
		y > (map_height - screen_height/(scale_y));
//	al_translate_transform(&cam , -centered->x + screen_width/(2*scale_x) , -centered->y + screen_height/(2*scale_y));
	al_scale_transform(cam , scale_x , scale_y);
	al_translate_transform(cam , -x*scale_x , -y*scale_y + pam_y/scale_y);
	
}